import logging from '../logging'
import {isEmpty} from '../utils'
import axios, {AxiosError} from 'axios';
import process from "process";

export type DockerCertificate = {
    username: string,
    password: string
}

export type RamStsCertificate = {
    accessKeyId: string,
    accessKeySecret: string
    securityToken: string
    accountId: string

}
export type NpmCertificate = {
    npmRepoConfigContent: string

}

export type OssRamStsCertificate = {
    accessKeyId: string,
    accessKeySecret: string
    securityToken: string
    ossPathPrefix: string
    bucketName: string

}

export type MavenCertificate = {
    mavenSettingsContent: string
}


export enum OssBucketType {
    ARTIFACT="ARTIFACT"
    , CACHE="CACHE"
    , ASSETS="ASSETS"

}

export type CodeupCertificate = {
    host: string,
    username: string,
    password: string
}

export type KubernetesCertificate = {
    type: string,
    kubeConfig: string,
    miranaProxy: string
    jwtToken: string
}

export type JenkinsCertificate = {
    jenkinsMaster: string
    jenkinsUsername: string
    jenkinsPassword: string
}

export type NugetCertificate = {
    nugetRepoConfigContent: string
}

export function getCertificateBasePath(): string {
    const serverURL = process.env[`FLOW_OPENAPI_URL`] as string
    if (isEmpty(serverURL)) {
        throw new Error("missing 'FLOW_OPENAPI_URL' env variables")
    }

    return `${serverURL}/openapi/certificates`
}

async function makeGenericRequest(url: string, params: any): Promise<Record<string, string>> {
    logging.info(`Get ${url}?flowJobToken=${(params.flowJobToken)}`);

    return axios.request({
        method: 'GET',
        url: url,
        params: params
    }).then(function (response) {
        const dataItems = response.data as Array<{ key: string, value: string }>;
        const certificateMap: Record<string, string> = {};
        for (const item of dataItems) {
            certificateMap[item.key] = item.value;
        }
        return certificateMap;
    }).catch((error: AxiosError) => {
        throw new Error(`error: ${error.code} ${JSON.stringify(error.response?.data)}`);
    });
}

export async function getCertificate<T>(
    url: string,
    params: any,
    maxRetries?: number
): Promise<T> {
    logging.debug(`Get ${url} with params: ${JSON.stringify(params)}`)

    if (maxRetries == null) {
        maxRetries = 3
    }

    let retriesTimes = 0
    while (retriesTimes < maxRetries) {
        try {
            return await axios
                .request({
                    method: 'GET',
                    url: url,
                    params: params
                })
                .then(function (response) {
                    return response.data as T
                })
                .catch((error: AxiosError) => {
                    throw new Error(
                        `error: ${error.code} ${JSON.stringify(
                            error.response?.data
                        )}`
                    )
                })
        } catch (err) {
            retriesTimes++
            logging.warning(
                `Get ${url} failed, ${err}, retry ${retriesTimes} times`
            )
        }
    }

    throw new Error(`Get ${url} failed, abort request.`)
}

export async function getMavenPrivateRepoCertificate(flowJobToken: string): Promise<Record<string, string>> {
    const getMavenPrivateRepoUrl = `${getCertificateBasePath()}/mavenPrivateRepo`;
    const params = {
        flowJobToken
    };
    return makeGenericRequest(getMavenPrivateRepoUrl, params);
}

export async function getCustomMavenSettingCertificate(flowJobToken: string): Promise<Record<string, string>> {
    const getMavenCustomSettingUrl = `${getCertificateBasePath()}/mavenCustomSetting`;
    const params = {
        flowJobToken
    };
    return makeGenericRequest(getMavenCustomSettingUrl, params);
}

export async function getNewMavenPrivateRepoCertificate(flowJobToken: string): Promise<MavenCertificate> {
    const getMavenPrivateRepoUrl = `${getCertificateBasePath()}/newMavenPrivateRepo`;
    const params = {
        flowJobToken
    };
    return getCertificate(getMavenPrivateRepoUrl, params) as Promise<MavenCertificate>;
}

export async function getNewCustomMavenSettingCertificate(flowJobToken: string): Promise<MavenCertificate> {
    const getMavenCustomSettingUrl = `${getCertificateBasePath()}/newMavenCustomSetting`;
    const params = {
        flowJobToken
    };
    return getCertificate(getMavenCustomSettingUrl, params) as Promise<MavenCertificate>;
}

export async function getNpmPrivateRepoCertificate(flowJobToken: string): Promise<NpmCertificate> {
    const getNpmPrivateRepoUrl = `${getCertificateBasePath()}/npmPrivateRepo`;
    const params = {
        flowJobToken
    };
    return getCertificate(getNpmPrivateRepoUrl, params) as Promise<NpmCertificate>;
}

export async function getDockerAcrEnterpriseCertificate(flowJobToken: string, serviceConnectionId: string, aliyunRegion: string, instanceName: string): Promise<DockerCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId,
        aliyunRegion,
        instanceName
    };
    return getCertificate(`${getCertificateBasePath()}/dockerAcrEnterprise`, params) as Promise<DockerCertificate>;
}

export async function getDockerAcrPersonalCertificate(flowJobToken: string, serviceConnectionId: string, aliyunRegion: string): Promise<DockerCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId,
        aliyunRegion
    };

    return getCertificate(`${getCertificateBasePath()}/dockerAcrPersonal`, params) as Promise<DockerCertificate>;
}

export async function getDockerCustomPersonalCertificate(flowJobToken: string, serviceConnectionId: string): Promise<DockerCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId
    };
    return getCertificate(`${getCertificateBasePath()}/dockerCustomPersonal`, params) as Promise<DockerCertificate>;
}

export async function getRamStsCertificate(flowJobToken: string, serviceConnectionId: string): Promise<RamStsCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId
    };
    return getCertificate(`${getCertificateBasePath()}/ramSts`, params) as Promise<RamStsCertificate>;
}

export async function getOssRamStsCertificate(flowJobToken: string, ossBucketType: OssBucketType): Promise<OssRamStsCertificate> {
    const params = {
        flowJobToken,
        ossBucketType: ossBucketType
    };
    return getCertificate(`${getCertificateBasePath()}/ossRamSts`, params) as Promise<OssRamStsCertificate>;
}

export async function getOssRamServiceConnectionCertificate(flowJobToken: string, serviceConnectionId: string): Promise<OssRamStsCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId
    };
    return getCertificate(`${getCertificateBasePath()}/ossRamSc`, params) as Promise<OssRamStsCertificate>;
}

export async function getCodeupCertificate(flowJobToken: string, serviceConnectionId: string): Promise<CodeupCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId
    };
    return getCertificate(`${getCertificateBasePath()}/codeup`, params) as Promise<CodeupCertificate>;
}

export async function getKubernetesCertificate(flowJobToken: string, serviceConnectionId: string): Promise<KubernetesCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId
    };
    return getCertificate(`${getCertificateBasePath()}/kubernetes`, params) as Promise<KubernetesCertificate>;
}

export async function getJenkinsCertificate(flowJobToken: string, serviceConnectionId: string): Promise<JenkinsCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId
    };
    return getCertificate(`${getCertificateBasePath()}/jenkins`, params) as Promise<JenkinsCertificate>;
}

export async function getNugetPrivateRepoCertificate(flowJobToken: string, serviceConnectionId: string, repoIds: string) : Promise<NugetCertificate> {
    const params = {
        flowJobToken,
        serviceConnectionId,
        repoIds
    };
    return getCertificate(`${getCertificateBasePath()}/nugetPrivateRepo`, params) as Promise<NugetCertificate>;
}